package com.openlogic.common.logic.log.strategy;

import java.util.Collection;
import java.util.Date;
import java.util.Map;

import org.noear.solon.cloud.CloudClient;
import org.noear.solon.core.event.AppBeanLoadEndEvent;
import org.noear.solon.core.event.EventListener;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.core.util.MultiMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.openlogic.api.logic.entity.RuleExecLog;
import com.openlogic.common.core.utils.DateUtils;
import com.openlogic.common.core.web.domain.model.LoginUser;
import com.openlogic.common.logic.annotation.RuleLog;
import com.openlogic.common.logic.constants.ExecConstants;
import com.openlogic.common.logic.event.RuleExecEventModel;
import com.openlogic.common.logic.event.RuleExecEventPublisher;
import com.openlogic.common.logic.utils.StackExceptionUtils;
import com.openlogic.common.security.utils.SecurityUtil;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;

/**
* @ClassName: RecordDecisionLogStrategy
* @Description: 记录日志策略类
* @author weiyongpeng
* @date 2024年10月9日 上午9:12:21
 */
public abstract class RecordDecisionLogStrategy implements EventListener<AppBeanLoadEndEvent>{
	
    private static final Logger log = LoggerFactory.getLogger(RecordDecisionLogStrategy.class);
    
	private RuleExecEventPublisher applicationEventPublisher = new RuleExecEventPublisher();
	

	public final void handleLog(final Context joinPoint, RuleLog ruleLog, final Throwable e, Object jsonResult, ThreadLocal<Long> startTime) {
        try {
        	Long endTime = System.currentTimeMillis();
            Long startT = startTime.get();
            startTime.remove();
            // *========规则执行数据库日志=========*//
            RuleExecEventModel operateLog = new RuleExecEventModel();
            // 执行状态
            operateLog.setStatus(ExecConstants.SUCCESS);
            // 规则Id
            long id = CloudClient.id().generate();
			String logId = String.valueOf(id); 
            LoginUser loginUser = SecurityUtil.getLoginUser();
            // 操作人
            String userName = ObjectUtil.isNotNull(loginUser) && ObjectUtil.isNotNull(loginUser)
                    ? loginUser.getUsername() : StrUtil.EMPTY;
            if (e != null) {
                operateLog.setStatus(ExecConstants.ERROR);
                operateLog.setErrorMsg(StackExceptionUtils.getStackTrace(e));
            }
            // 处理设置注解上的参数
            getControllerMethodDescription(joinPoint, ruleLog, operateLog, jsonResult);
            operateLog.setLogId(logId);
            operateLog.setRuleType(ruleLog.ruleType().getCode());
            operateLog.setOperateDate(DateUtils.getDate());
            operateLog.setExecStartTime(new Date(startT));
            operateLog.setExecEndTime(new Date(endTime));
            operateLog.setExecTime((endTime - startT));
            operateLog.setOperateNo(userName);
            // log.info("ruleExecLog:"+operateLog);
            // 保存数据库
            // 事件发布-规则执行完毕后发布事件，附加功能可在监听处实现，解耦
            applicationEventPublisher.publishLogListener(operateLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
        }
    }
	
	/**
     * 
    * 描述：获取请求的参数，放到log中
    * @Title: setRequestValue
    * @param joinPoint
    * @param operLog
    * @throws Exception
    * @author weiyongpeng
    * @date  2024年5月7日 上午10:21:03
     */
	protected void setRequestValue(Context joinPoint, RuleExecLog operLog) throws Exception {
    	// 获取请求参数里的dataInfo即可，然后把规则执行json也需要保存
    	argsArrayToString(joinPoint.paramMap(),operLog);
    }

    /**
     * 
    * 描述：判断是否需要过滤的对象。
    * @Title: isFilterObject
    * @param o
    * @return
    * @author weiyongpeng
    * @date  2024年5月7日 上午10:21:24
     */
    @SuppressWarnings("rawtypes")
    protected boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return clazz.getComponentType().isAssignableFrom(UploadedFile.class);
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof UploadedFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.entrySet()) {
                Map.Entry entry = (Map.Entry) value;
                return entry.getValue() instanceof UploadedFile;
            }
        }
		return o instanceof UploadedFile;
    }

	/**
	* 描述：模板方法获取不同类型的Controller参数
	* @Title: getControllerMethodDescription
	* @param joinPoint
	* @param decisionTreeLog
	* @param operateLog
	* @param jsonResult
	* @author weiyongpeng
	 * @throws Exception 
	* @date  2024年10月9日 上午9:19:54
	 */
	protected abstract void getControllerMethodDescription(Context joinPoint, RuleLog ruleLog, RuleExecLog operateLog, Object jsonResult) throws Exception;
	
	/**
	* 描述：获取Controller接口参数模板方法
	* @Title: argsArrayToString
	* @param paramMap
	* @param operLog
	* @return
	* @author weiyongpeng
	* @date  2024年10月9日 上午9:47:44
	 */
	protected abstract String argsArrayToString(MultiMap<String> paramMap, RuleExecLog operLog);
}
